package com.bz.sunmipay.activity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.baizhi.baseapp.activity.BaseActivity;
import com.baizhi.baseapp.widget.WToast;
import com.bz.sunmipay.R;
import com.bz.sunmipay.application.MyApplication;
import com.bz.sunmipay.controller.GlobalDataHolder;
import com.bz.sunmipay.database.DBHelper;
import com.bz.sunmipay.database.PaymentDetailDatabase;
import com.bz.sunmipay.model.PaymentDetail;
import com.bz.sunmipay.payment.CheckCardCallbackV2Wrapper;
import com.bz.sunmipay.payment.PaymentHelp;
import com.bz.sunmipay.payment.emv.EmvUtil;
import com.bz.sunmipay.utils.AppUtils;
import com.bz.sunmipay.utils.ByteUtil;
import com.bz.sunmipay.utils.Constant;
import com.bz.sunmipay.utils.IntentUtils;
import com.bz.sunmipay.utils.LogUtil;
import com.bz.sunmipay.utils.ThreadPoolUtil;
import com.sunmi.pay.hardware.aidlv2.AidlConstantsV2;
import com.sunmi.pay.hardware.aidlv2.bean.EMVCandidateV2;
import com.sunmi.pay.hardware.aidlv2.bean.EMVTransDataV2;
import com.sunmi.pay.hardware.aidlv2.emv.EMVListenerV2;
import com.sunmi.pay.hardware.aidlv2.readcard.CheckCardCallbackV2;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import de.wirecard.paymentsdk.WirecardPaymentResponse;
import de.wirecard.paymentsdk.WirecardResponseError;
import de.wirecard.paymentsdk.WirecardResponseListener;
import de.wirecard.paymentsdk.api.models.json.helpers.TransactionState;

/**
 * 支付方式页
 * <p>
 * Created by Administrator on 2019/12/5.
 */
public class PaymentPatternActivity extends BaseActivity {
    private String mAmount;
    private String mVat;

    private String mCardNo; // card number
    private int mCardType;  // card type

    private Map<String, String> configMap;

    private static final int PIN_CLICK_CONFIRM = 4;
    private static final int EMV_FINAL_APP_SELECT = 7;
    private static final int EMV_TRANS_FAIL = 999;

    private PaymentDetail mPaymentDetailData;

    private Looper mLooper = Looper.myLooper();
    private Handler mHandler = new Handler(mLooper) {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case PIN_CLICK_CONFIRM:
                    mockRequestToServer();
                    break;
                case EMV_FINAL_APP_SELECT:
                    importFinalAppSelectStatus(0);
                    break;
                case EMV_TRANS_FAIL:
                    mPaymentDetailData.paymentResult = "0";
                    showToastAndExit(msg.obj + "", false);
                    break;
            }
        }
    };
    private PaymentDetailDatabase mPaymentDetailDatabase;
    private boolean isManualCancel;

    /**
     * 展示提示并 退出
     *
     * @param msg
     * @param isManualCancel 是否手动取消（弹窗）
     */
    private void showToastAndExit(final String msg, final boolean isManualCancel) {
        this.isManualCancel = isManualCancel;
        updateDatabase(mPaymentDetailData);
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                cancelCheckCard();
                dismissProgress();
                Toast.makeText(PaymentPatternActivity.this, msg, Toast.LENGTH_SHORT).show();
                if (!isManualCancel) {
                    IntentUtils.goToPaymentFailPage(PaymentPatternActivity.this);
                }
                finish();
            }
        });
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentLayout(R.layout.activity_payment_pattern);
        setLeftContentIcon(R.mipmap.back);
        setRightContentIcon(R.mipmap.home);
        setCenterText("PAYMENT");
        mAmount = getIntent().getStringExtra("amount");
        mVat = getIntent().getStringExtra("vat");
        float parseLong = AppUtils.convertToFloat(mAmount, 0);
        if (parseLong < 0) {
            WToast.showToast("Please enter the correct consumption amount");
            finish();
            return;
        }
        mPaymentDetailDatabase = new PaymentDetailDatabase(this);
        databaseParams();

        initData();
        checkCard();
    }

    private void initData() {
        configMap = EmvUtil.getConfig(EmvUtil.COUNTRY_RUSSIA);
        ThreadPoolUtil.executeInCachePool(
                new Runnable() {
                    @Override
                    public void run() {
                        EmvUtil.initKey();
                        EmvUtil.initAidAndRid();
                        EmvUtil.setTerminalParam(configMap);
                    }
                }
        );
    }

    private void databaseParams() {
        mPaymentDetailData = new PaymentDetail();
        mPaymentDetailData.paymentId = UUID.randomUUID().toString();
        mPaymentDetailData.userId = GlobalDataHolder.getInstance(this).getUid();
        mPaymentDetailData.userName = GlobalDataHolder.getInstance(this).getUserInfo().getNickname();
        mPaymentDetailData.amount = mAmount;
        mPaymentDetailData.paymentResult = "0";
        mPaymentDetailData.paymentType = "0";
        addDatabase(mPaymentDetailData);
    }

    private void checkCard() {
        try {
            Log.e("dd--", "checkCard");
            //for rf & nfc
            MyApplication.mEMVOptV2.abortTransactProcess();
            MyApplication.mEMVOptV2.initEmvProcess();

            showCancelableProcess("swipe, wave or insert", new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mPaymentDetailData.paymentResult = "-1";
                    showToastAndExit("trade cancel", true);
                }
            });
            int cardType = AidlConstantsV2.CardType.MAGNETIC.getValue() | AidlConstantsV2.CardType.NFC.getValue() |
                    AidlConstantsV2.CardType.IC.getValue();
            MyApplication.mReadCardOptV2.checkCard(cardType, mCheckCardCallback, 60);
        } catch (Exception e) {
            e.printStackTrace();
            WToast.showToast("recognition failure");
        }
    }

    private CheckCardCallbackV2 mCheckCardCallback = new CheckCardCallbackV2Wrapper() {

        @Override
        public void findMagCard(Bundle bundle) throws RemoteException {
            Log.e("dd--", "findMagCard");
            String track1 = bundle.getString("TRACK1");
            String track2 = bundle.getString("TRACK2");
            String track3 = bundle.getString("TRACK3");
            if (track2 != null) {
                int index = track2.indexOf("=");
                if (index != -1) {
                    mCardNo = track2.substring(0, index);
                }
            }
            Log.e("dd--", "mCardNo: " + mCardNo);
            if (mCardNo != null && mCardNo.length() > 0) {
                mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget();
            } else {
                Toast.makeText(PaymentPatternActivity.this, "Get card information error", Toast.LENGTH_SHORT).show();
                dismissProgress();
            }
            mPaymentDetailData.paymentType = AidlConstantsV2.CardType.MAGNETIC.getValue() + "";
        }

        @Override
        public void findICCard(String atr) throws RemoteException {
            Log.e("dd---", "findICCard:" + atr);
            mCardType = AidlConstantsV2.CardType.IC.getValue();
            mPaymentDetailData.paymentType = AidlConstantsV2.CardType.IC.getValue() + "";
            transactProcess();
        }

        @Override
        public void findRFCard(String uuid) throws RemoteException {
            Log.e("dd---", "findRFCard:" + uuid);
            mCardType = AidlConstantsV2.CardType.NFC.getValue();
            mPaymentDetailData.paymentType = AidlConstantsV2.CardType.NFC.getValue() + "";
            transactProcess();
        }

        @Override
        public void onError(int code, String message) throws RemoteException {
            String error = "onError:" + message + " -- " + code;
            Log.e("dd--", error);
            mPaymentDetailData.paymentResult = "0";
            showToastAndExit(message, false);
        }

    };

    private void transactProcess() {
        Log.e("dd--", "transactProcess");
        try {
            EMVTransDataV2 emvTransData = new EMVTransDataV2();

            final float amountFloat = AppUtils.convertToFloat(mAmount, 0);
            Float aFloat = Float.valueOf(amountFloat);
            int intValue = aFloat.intValue();
            final String amount = intValue + "";
            emvTransData.amount = amount;
            emvTransData.flowType = 1;
            emvTransData.cardType = mCardType;
            MyApplication.mEMVOptV2.transactProcess(emvTransData, mEMVListener);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private EMVListenerV2 mEMVListener = new EMVListenerV2.Stub() {

        @Override
        public void onWaitAppSelect(List<EMVCandidateV2> list, boolean b) throws RemoteException {
            Log.e("dd--", "onWaitAppSelect:");
        }

        @Override
        public void onAppFinalSelect(String tag9F06value) throws RemoteException {
            Log.e("dd--", "onAppFinalSelect tag9F06value:" + tag9F06value);
            initEmvTlvData();
            if (tag9F06value != null && tag9F06value.length() > 0) {
                boolean isVisa = tag9F06value.startsWith("A000000003");
                boolean isMaster = tag9F06value.startsWith("A000000004")
                        || tag9F06value.startsWith("A000000005");
                boolean isUnionPay = tag9F06value.startsWith("A000000333");
                boolean isAmericanExpress = tag9F06value.startsWith("A000000025");
                boolean isJCB = tag9F06value.startsWith("A000000065");
                boolean isRupay = tag9F06value.startsWith("A000000524");
                if (isVisa) {
                    // VISA(PayWave)
                    LogUtil.e(Constant.TAG, "detect VISA card");
//                    mAppSelect = 1;
                    // set PayWave tlv data
                    String[] tagsPayWave = {
                            "DF8124", "DF8125", "DF8126"
                    };
                    String[] valuesPayWave = {
                            "999999999999", "999999999999", "000000000000"
                    };
                    MyApplication.mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PAYWAVE, tagsPayWave, valuesPayWave);
                } else if (isMaster) {
                    // MasterCard(PayPass)
                    LogUtil.e(Constant.TAG, "detect MasterCard card");
//                    mAppSelect = 2;
                    // set PayPass tlv data
                    String[] tagsPayPass = {
                            "DF8117", "DF8118", "DF8119", "DF811F", "DF811E", "DF812C",
                            "DF8123", "DF8124", "DF8125", "DF8126",
                            "DF811B", "DF811D", "DF8122", "DF8120", "DF8121"
                    };
                    String[] valuesPayPass = {
                            "E0", "F8", "F8", "E8", "00", "00",
                            "000000000000", "000000100000", "999999999999", "000000100000",
                            "30", "02", "0000000000", "000000000000", "000000000000"
                    };
                    MyApplication.mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PAYPASS, tagsPayPass, valuesPayPass);
                } else if (isUnionPay) {
                    // UnionPay
//                    mAppSelect = 0;
                    LogUtil.e(Constant.TAG, "detect UnionPay card");
                }
            }
//            mProcessStep = EMV_FINAL_APP_SELECT;
            mHandler.obtainMessage(EMV_FINAL_APP_SELECT, tag9F06value).sendToTarget();
        }

        @Override
        public void onConfirmCardNo(String s) throws RemoteException {
            Log.e("dd--", "onConfirmCardNo cardNo:" + s);
            mCardNo = s;
            importCardNoStatus(0);
            mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget();
        }

        @Override
        public void onRequestShowPinPad(int i, int i1) throws RemoteException {
            Log.e("dd--", "onRequestShowPinPad:");
            importPinInputStatus(0);
        }

        @Override
        public void onRequestSignature() throws RemoteException {
            Log.e("dd--", "onRequestSignature:");
        }

        @Override
        public void onCertVerify(int i, String s) throws RemoteException {
            Log.e("dd--", "onCertVerify:");
        }

        @Override
        public void onOnlineProc() throws RemoteException {
            Log.e("dd--", "onOnlineProc:");
            importOnlineProcessStatus(0);
        }

        @Override
        public void onCardDataExchangeComplete() throws RemoteException {
            Log.e("dd--", "onCardDataExchangeComplete:");
        }

        @Override
        public void onTransResult(int code, final String desc) throws RemoteException {
            Log.e("dd---", "onTransResult code:" + code + " desc:" + desc);
            if (code != 0) {
                mHandler.obtainMessage(EMV_TRANS_FAIL, code, code, desc).sendToTarget();
            }
        }

        @Override
        public void onConfirmationCodeVerified() throws RemoteException {
            Log.e("dd--", "onConfirmationCodeVerified:");
        }

        @Override
        public void onRequestDataExchange(String s) throws RemoteException {
            Log.e("dd--", "onRequestDataExchange:");
        }
    };

    private void importCardNoStatus(int status) {
        LogUtil.e(Constant.TAG, "importCardNoStatus status:" + status);
        try {
            MyApplication.mEMVOptV2.importCardNoStatus(status);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void importPinInputStatus(int inputResult) {
        LogUtil.e(Constant.TAG, "importPinInputStatus:" + inputResult);
        try {
            int mPinType = 0;
            MyApplication.mEMVOptV2.importPinInputStatus(mPinType, inputResult);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void importOnlineProcessStatus(int status) {
        LogUtil.e(Constant.TAG, "importOnlineProcessStatus status:" + status);
        try {
            String[] tags = {
                    "71", "72", "91", "8A", "89"
            };
            String[] values = {
                    "", "", "", "", ""
            };
            byte[] out = new byte[1024];
            int len = MyApplication.mEMVOptV2.importOnlineProcStatus(status, tags, values, out);
            if (len < 0) {
                LogUtil.e(Constant.TAG, "importOnlineProcessStatus error,code:" + len);
            } else {
                byte[] bytes = Arrays.copyOf(out, len);
                String hexStr = ByteUtil.bytes2HexStr(bytes);
                LogUtil.e(Constant.TAG, "importOnlineProcessStatus outData:" + hexStr);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initEmvTlvData() {
        try {
            // set normal tlv data
            String[] tags = {"5F2A", "5F36",};
            String[] values = {configMap.get("5F2A"), configMap.get("5F36"),};
            MyApplication.mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL, tags, values);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private void mockRequestToServer() {
        if (TextUtils.isEmpty(mCardNo)) {
            WToast.showToast("Card number cannot be empty");
            return;
        }
        dismissProgress();
        showCancelableProcess("In payment...", new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPaymentDetailData.paymentResult = "-1";
                showToastAndExit("payment cancel", true);
            }
        });
//        4271149787014678
        PaymentHelp.getInstance(this).makeSimplePayment(mCardNo, "", mAmount, new WirecardResponseListener() {
            @Override
            public void onResponse(WirecardPaymentResponse wirecardPaymentResponse) {
                dismissProgress();
                Log.e("dd--", "onMessage: " + wirecardPaymentResponse.getTransactionState().getValue());
                Log.e("dd--", "onDesc: " + wirecardPaymentResponse.getStatuses().getStatus()[0].getDescription());
                if (wirecardPaymentResponse.getTransactionState() == TransactionState.SUCCESS) {
                    mPaymentDetailData.paymentResult = "1";
                    if (!isManualCancel) {
                        IntentUtils.goToPaymentSuccessPage(PaymentPatternActivity.this);
                    }
                } else if (wirecardPaymentResponse.getTransactionState() == TransactionState.FAILED) {
                    mPaymentDetailData.paymentResult = "0";
                    if (!isManualCancel) {
                        IntentUtils.goToPaymentFailPage(PaymentPatternActivity.this);
                        WToast.showToast(wirecardPaymentResponse.getStatuses().getStatus()[0].getDescription());
                    }
                }
                updateDatabase(mPaymentDetailData);
                finish();
            }

            @Override
            public void onError(WirecardResponseError wirecardResponseError) {
                dismissProgress();
                Log.e("dd--", "onErrorMessage: " + wirecardResponseError.getErrorMessage());
                Log.e("dd--", "onErrorCode: " + wirecardResponseError.getErrorCode());
                mPaymentDetailData.paymentResult = "0";
                updateDatabase(mPaymentDetailData);
                if (!isManualCancel) {
                    IntentUtils.goToPaymentFailPage(PaymentPatternActivity.this);
                    WToast.showToast(wirecardResponseError.getErrorMessage());
                }
                finish();
            }
        });
    }

    private void addDatabase(PaymentDetail paymentDetail) {
        mPaymentDetailDatabase.insert(paymentDetail, DBHelper.TABLE_NAME);
    }

    private void updateDatabase(PaymentDetail paymentDetail) {
        mPaymentDetailDatabase.update(paymentDetail, DBHelper.TABLE_NAME);
    }

    private void importFinalAppSelectStatus(int status) {
        try {
            LogUtil.e(Constant.TAG, "importFinalAppSelectStatus status:" + status);
            MyApplication.mEMVOptV2.importAppFinalSelectStatus(status);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void handleClickEvent(int event) {
        super.handleClickEvent(event);
        if (event == RIGHT_BUTTON) {
            IntentUtils.goToHome(this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        cancelCheckCard();
    }

    private void cancelCheckCard() {
        try {
            MyApplication.mReadCardOptV2.cardOff(AidlConstantsV2.CardType.NFC.getValue());
            MyApplication.mReadCardOptV2.cancelCheckCard();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
